﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Documents;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.IO;
using System.Windows.Markup;
using System.ComponentModel;

namespace DiagramDesigner
{
public class PointLineAdorner : Adorner
    {
        // Canvas to hold the thumbs so they can be moved in response to the user
        //private Canvas _cnvThumbs;

        // Cropping adorner uses Thumbs for visual elements.  
        // The Thumbs have built-in mouse input handling.
        private BasicThumb _crtLeft, _crtRight;

        private Thumb _crtCenter;

        // To store and manage the adorner's visual children.
        private VisualCollection _vc;

        private double scaleX, scaleY;


        #region Properties
        #endregion

        #region Routed Events
        public static readonly RoutedEvent LineChangedEvent = EventManager.RegisterRoutedEvent(
            "LineChanged",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof(PointLineAdorner));

        public event RoutedEventHandler LineChanged
        {
            add
            {
                base.AddHandler(PointLineAdorner.LineChangedEvent, value);
            }
            remove
            {
                base.RemoveHandler(PointLineAdorner.LineChangedEvent, value);
            }
        }
        #endregion

        #region Dependency Properties
        #endregion

        #region Constructor        

        public PointLineAdorner(PointLine adornedLine)
            : base(adornedLine)
        {
            _vc = new VisualCollection(this);

            BuildCorner(ref _crtLeft, Cursors.SizeAll);
            BuildCorner(ref _crtRight, Cursors.SizeAll);
            
            //_crtCenter = new Thumb();//adornedLine);
            //_crtCenter.Name = "myThumb";
            //_crtCenter.Cursor = Cursors.ScrollAll;
            //_vc.Add(_crtCenter);            

            //string xaml = "<ControlTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' TargetType=\"Thumb\">" +
            //    "<Line x:Name=\"line\" Stroke='Black' StrokeThickness='4' X1='{Binding Path=\"DataContext.StartPoint.X\"}' " +
            //    "Y1='{Binding Path=\"DataContext.StartPoint.Y\"}' X2='{Binding Path=\"DataContext.EndPoint.X\"}' Y2='{Binding Path=\"DataContext.EndPoint.Y\"}'/>" + 
            //    "</ControlTemplate>";
            
            //string xaml = "<ControlTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' TargetType=\"Thumb\">" +
            //    "<Rectangle x:Name=\"rect\" Fill='Transparent' Stroke='Transparent' StrokeThickness='3' HorizontalAlignment='Left' VerticalAlignment='Top' />" + 
            //    "</ControlTemplate>";
            //MemoryStream sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
            //ParserContext pc = new ParserContext();
            //pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
            //pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
            //_crtCenter.Template = (ControlTemplate)XamlReader.Load(sr, pc);            
            
            PointLine l = adornedLine;// AdornedElement as PointLine;
            _crtLeft.SetPos(l.StartPoint.X, l.StartPoint.Y);
            _crtRight.SetPos(l.EndPoint.X, l.EndPoint.Y);
            //_crtCenter.SetPos(l.StartPoint.X, l.StartPoint.Y);
            
            // Add handlers for Cropping.
            _crtRight.DragDelta += new DragDeltaEventHandler(HandleRight);
            _crtLeft.DragDelta += new DragDeltaEventHandler(HandleLeft);
            //_crtCenter.DragDelta += new DragDeltaEventHandler(HandleCenter);

            //DependencyPropertyDescriptor desc1 = DependencyPropertyDescriptor.FromProperty(
            //    PointLine.StartPointProperty, typeof(PointLine));
            //DependencyPropertyDescriptor desc2 = DependencyPropertyDescriptor.FromProperty(
            //    PointLine.EndPointProperty, typeof(PointLine));
            //desc1.AddValueChanged(adornedLine, new EventHandler(adornedLinePointChanged));

            // We have to keep the clipping interior withing the bounds of the adorned element
            // so we have to track it's size to guarantee that...
            //FrameworkElement fel = adornedElement as FrameworkElement;

            //if (fel != null)
            //{
            //    fel.SizeChanged += new SizeChangedEventHandler(AdornedElement_SizeChanged);
            //}
        }
        #endregion

        #region Thumb handlers
        // Generic handler for Cropping
        private void HandleThumb(
            double drcL,
            double drcR,
            double dx,
            double dy)
        {
            PointLine l = AdornedElement as PointLine;

            double x1 = l.StartPoint.X, y1 = l.StartPoint.Y;
            double x2 = l.EndPoint.X, y2 = l.EndPoint.Y;
                        
            if (drcL != 0) 
            {
                x1 += drcL * dx;
                y1 += drcL * dy;
            }
            if (drcR != 0) 
            {
                x2 += drcR * dx;
                y2 += drcR * dy;
            }

            DependencyObject obj = VisualTreeHelper.GetParent(l);

            FrameworkElement c = obj as FrameworkElement;
            if (c != null)
            {
                x1 = Math.Min(Math.Max(0, x1), c.ActualWidth);
                x2 = Math.Min(Math.Max(0, x2), c.ActualWidth);
                y1 = Math.Min(Math.Max(0, y1), c.ActualHeight);
                y2 = Math.Min(Math.Max(0, y2), c.ActualHeight);
            }

            l.StartPoint = new Point(x1, y1);
            l.EndPoint = new Point(x2, y2);
            SetThumbs(x1,y1,x2,y2);

            

            RaiseEvent(new RoutedEventArgs(LineChangedEvent, this));
        }

        private void HandleCenter(object sender, DragDeltaEventArgs args)
        {
            if (sender is Thumb)
            {
                //var myThumb = sender as Thumb;
                //if (myThumb != null)
                //{
                //    var myUserControl = myThumb.Template.FindName("line", myThumb) as Line;
                //    if (myUserControl != null)
                //    {
                //        myUserControl.X1 = myUserControl.X1 + args.HorizontalChange;
                //        myUserControl.X2 = myUserControl.X2 + args.HorizontalChange;
                //        myUserControl.Y1 = myUserControl.Y1 + args.VerticalChange;
                //        myUserControl.Y2 = myUserControl.Y2 + args.VerticalChange;
                //    }
                //}

                HandleThumb(
                    1, 1,
                    args.HorizontalChange * scaleX,
                    args.VerticalChange * scaleY);
            }
        }

        // Handler for Cropping from the bottom-left.
        private void HandleLeft(object sender, DragDeltaEventArgs args)
        {
            if (sender is BasicThumb)
            {
                HandleThumb(
                    1, 0,
                    args.HorizontalChange * scaleX,
                    args.VerticalChange * scaleY);
            }
        }

        // Handler for Cropping from the bottom-right.
        private void HandleRight(object sender, DragDeltaEventArgs args)
        {
            if (sender is BasicThumb)
            {
                HandleThumb(
                    0, 1,
                    args.HorizontalChange * scaleX,
                    args.VerticalChange * scaleY);
            }
        }       
        #endregion


        #region Arranging/positioning
        private void SetThumbs(double dx1, double dy1, double dx2, double dy2)
        {
            //_crtLeft.SetPos(dx1, dy1);
            //_crtRight.SetPos(dx2, dy2);
            //_crtCenter.AdjustPos(dx1, dy1);
        }
        
        // Arrange the Adorners
        protected override Size ArrangeOverride(Size finalSize)
        {
            // desiredWidth and desiredHeight are the width and height of the element that's being adorned.
            // These will be used to place the ResizingAdorner at the corners of the adorned element.
            double desiredWidth = AdornedElement.DesiredSize.Width;
            double desiredHeight = AdornedElement.DesiredSize.Height;
            // adornerWidth & adornerHeight are used for placement as well.
            double adornerWidth = this.DesiredSize.Width;
            double adornerHeight = this.DesiredSize.Height;
            PointLine l = AdornedElement as PointLine;
            double w = _crtLeft.DesiredSize.Width;
            double h = _crtLeft.DesiredSize.Height;

            _crtLeft.Arrange(new Rect(l.StartPoint.X - w/2, l.StartPoint.Y - h/2, w, h));
            _crtRight.Arrange(new Rect(l.EndPoint.X - w / 2, l.EndPoint.Y - h / 2, w, h));
            
            //_crtLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));            
            //_crtRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));

            //var myUserControl = _crtCenter.Template.FindName("line", _crtCenter) as Line;
            //if (myUserControl != null)
            //{
            //    //myUserControl.X1 = l.StartPoint.X;
            //    //myUserControl.Y1 = l.StartPoint.Y;
            //    //myUserControl.X2 = l.EndPoint.X;
            //    //myUserControl.Y2 = l.EndPoint.Y;
            //    myUserControl.X1 = 0;
            //    myUserControl.Y1 = 0;
            //    myUserControl.X2 = l.EndPoint.X - l.StartPoint.X;
            //    myUserControl.Y2 = l.EndPoint.Y - l.StartPoint.Y;
            //}
            //_crtCenter.Arrange(new Rect(Math.Min(l.StartPoint.X, l.EndPoint.X),
            //    Math.Min(l.StartPoint.Y, l.EndPoint.Y), Math.Abs(l.EndPoint.X - l.StartPoint.X), Math.Abs(l.EndPoint.Y - l.StartPoint.Y)));

            //var myUserControl = _crtCenter.Template.FindName("rect", _crtCenter) as Rectangle;
            //if (myUserControl != null)
            //{                                
            //    myUserControl.Width = Math.Abs(l.EndPoint.X - l.StartPoint.X);
            //    myUserControl.Height = Math.Abs(l.EndPoint.Y - l.StartPoint.Y);
            //}
            //_crtCenter.Arrange(new Rect(Math.Min(l.StartPoint.X, l.EndPoint.X),
            //    Math.Min(l.StartPoint.Y, l.EndPoint.Y), Math.Abs(l.EndPoint.X - l.StartPoint.X), Math.Abs(l.EndPoint.Y - l.StartPoint.Y)));

            // Return the final size.
            return finalSize;
        }

        #endregion       

        #region Helper functions
        private Thickness AdornerMargin()
        {
            Thickness thick = new Thickness(0);
            if (AdornedElement is FrameworkElement)
            {
                thick = ((FrameworkElement)AdornedElement).Margin;
            }
            return thick;
        }

        private void BuildCorner(ref BasicThumb crt, Cursor crs)
        {
            if (crt != null) return;
            crt = new BasicThumb();
            // Set some arbitrary visual characteristics.
            crt.Cursor = crs;
            _vc.Add(crt);
            //_cnvThumbs.Children.Add(crt);
        }

        #endregion


        public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
        {
            scaleX = 1; scaleY = 1;

            MatrixTransform mt = transform as MatrixTransform;
            if (mt != null)
            {
                scaleX = 1.0/Math.Sqrt(mt.Matrix.M11 * mt.Matrix.M11 + mt.Matrix.M12 * mt.Matrix.M12);
                scaleY = 1.0/Math.Sqrt(mt.Matrix.M21 * mt.Matrix.M21 + mt.Matrix.M22 * mt.Matrix.M22);

                _crtLeft.RenderTransform = new ScaleTransform(scaleX, scaleY);
                _crtLeft.RenderTransformOrigin = new Point(0.5, 0.5);
                _crtRight.RenderTransform = new ScaleTransform(scaleX, scaleY);
                _crtRight.RenderTransformOrigin = new Point(0.5, 0.5);
            }
            return base.GetDesiredTransform(transform);
        }

        #region Visual tree overrides
        // Override the VisualChildrenCount and GetVisualChild properties to interface with 
        // the adorner's visual collection.
        protected override int VisualChildrenCount { get { return _vc.Count; } }
        protected override Visual GetVisualChild(int index) { return _vc[index]; }
        #endregion        
    }
}

